package com.hgy.chapter3.aspect;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;

import com.hgy.framework.annotation.Aspect;
import com.hgy.framework.annotation.Controller;
import com.hgy.framework.proxy.AspectProxy;
import com.hgy.plugin.security.annotation.Authenticated;
import com.hgy.plugin.security.annotation.Guest;
import com.hgy.plugin.security.annotation.HasPermissions;
import com.hgy.plugin.security.annotation.HasRoles;
import com.hgy.plugin.security.annotation.User;
import com.hgy.plugin.security.exception.AuthzException;

/**
 * 授权注解切面
 * <br>使用前置增强确保在方法执行前进行认证处理
 *
 * @author alone
 *
 */
//TODO 关于异常类处理
@Aspect(Controller.class)
public class AuthzAnotationAspect extends AspectProxy{
	

	/**
	 * 授权注解功能注解类数组
	 */
	@SuppressWarnings("rawtypes")
	private static final Class[] ANOTATION_CALSS_ARRAY = {
			User.class, Guest.class, Authenticated.class, HasRoles.class, HasPermissions.class
		};
	
	/**
	 * 前置增强
	 */
	@Override
	public void before(Class<?> cls, Method method, Object[] params) {
		
		Annotation annotation = getAnotation(cls, method);
		if(annotation != null){
			Class<? extends Annotation> annotationType = annotation.annotationType();
			 if (annotationType.equals(Authenticated.class)) {
	                handleAuthenticated();
	            } else if (annotationType.equals(User.class)) {
	                handleUser();
	            } else if (annotationType.equals(Guest.class)) {
	                handleGuest();
	            } else if (annotationType.equals(HasRoles.class)) {
	                handleHasRoles((HasRoles) annotation);
	            } else if (annotationType.equals(HasPermissions.class)) {
	                handleHasPermissions((HasPermissions) annotation);
	            }
		}
	}
	
	/**
	 * 从目标类与目标方法中获取对应的注解信息
	 * 
	 * @param cls
	 * @param method
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private Annotation getAnotation(Class<?> cls, Method method) {

		for (Class<? extends Annotation> annotationClass : ANOTATION_CALSS_ARRAY) {
			// 判断方法上是否有目标注解
			if(method.isAnnotationPresent(annotationClass)){
				return method.getAnnotation(annotationClass);
			}
			// 判断类上是否有目标注解
			if(cls.isAnnotationPresent(annotationClass)){
				return cls.getAnnotation(annotationClass);
			}
		}
		//若都没有 则返回null
		return null;
	}
	
	private void handleAuthenticated() {
        Subject currentUser = SecurityUtils.getSubject();
        if (!currentUser.isAuthenticated()) {
            throw new AuthzException("当前用户尚未认证");
        }
    }

    private void handleUser() {
        Subject currentUser = SecurityUtils.getSubject();
        PrincipalCollection principals = currentUser.getPrincipals();
        if (principals == null || principals.isEmpty()) {
            throw new AuthzException("当前用户尚未登录");
        }
    }

    private void handleGuest() {
        Subject currentUser = SecurityUtils.getSubject();
        PrincipalCollection principals = currentUser.getPrincipals();
        if (principals != null && !principals.isEmpty()) {
            throw new AuthzException("当前用户不是访客");
        }
    }

    private void handleHasRoles(HasRoles hasRoles) {
        String roleName = hasRoles.value();
        Subject currentUser = SecurityUtils.getSubject();
        if (!currentUser.hasRole(roleName)) {
            throw new AuthzException("当前用户没有指定角色，角色名：" + roleName);
        }
    }

    private void handleHasPermissions(HasPermissions hasPermissions) {
        String permissionName = hasPermissions.value();
        Subject currentUser = SecurityUtils.getSubject();
        if (!currentUser.isPermitted(permissionName)) {
            throw new AuthzException("当前用户没有指定权限，权限名：" + permissionName);
        }
    }
}
